Spring Security Note-2
Spring MVC开发RESTful API
在这一篇笔记中,将开发REST风格的API服务接口,并且在后面的笔记中的认证和授权中,对这些API进行安全保护;
并且会有学习到,如何拦截服务接口来提供一些统一的功能;
如何通过多线程提高服务的性能;
如何自动生成API文档;
伪造服务;
RESTful简介
传统API VS RESTful API
NAME | API | METHOD | RESTful API | METHOD |
---|---|---|---|---|
查询 | /user/query?name=tom | GET | /user?name=tom | GET |
详情 | /user/getInfo?id=1 | GET | /user/1 | GET |
创建 | /user/create?name=tom | POST | /user | POST |
修改 | /user/update?id=1&name=tom | POST | /user/1 | PUT |
删除 | /user/delete?id=1 | GET | /user/1 | DELETE |
RESTful API
1.用URL描述资源,而不是描述行为;
2.使用HTTP方法描述行为,使用HTTP状态码来表示不同的结果;
3.使用JSON交互数据;
4.RESTful只是一种风格,不是强制的标准;
REST成熟度模型
Level0:使用HTTP作为传输方式;
Level1:引入资源概念;每个资源都有对应的URL;
Level2(RESTful):使用HTTP方法进行不同的操作;使用HTTP状态码来表示不同的结果;
Level3:使用超媒体;在资源的表达中包含了链接信息;
用户查询请求
编写针对RESTful API的测试用例
首先引入针对Spring Boot的测试框架;
1 | <dependency> |
1 | (SpringRunner.class) |
使用注解声明RESTful API
@RestController 标明这个Controller提供REST API
@RequestMapping 及其变体(映射HTTP请求URL到JAVA方法)
@RequestParam 映射请求参数到JAVA方法的参数
@PageableDefault 指定分页参数默认值
1 |
|
在RESTful API中传递参数
此时我们在请求中,加入
1 | public List<User> query(@RequestParam String username){} |
required :指明参数是否必传;
name :指明参数在URL传递的名称;
defaultValue:当参数为空时的默认值;
那么在测试用例中,我们对于的需要加上参数,不然将报出400的错误;
1 | .param("username","rex") |
将查询的条件,封装成一个对象,直接传入查询的对象;
1 | public class UserQueryCondition { |
1 | public List<User> query(UserQueryCondition condition, @PageableDefault(size = 17,page = 2,sort = "username,asc") Pageable pageable){ |
1 | .param("username","rex") |
用户详情请求
1 |
|
@PathVaribale 映射URL片段到JAVA方法的参数
1 | "/user/{id}",method = RequestMethod.GET) (value = |
在URL声明中使用正则表达式
希望传入的id必须是数字,使用正则表达式规范传入的参数;
1 | "/user/{id:\\d+}",method = RequestMethod.GET) (value = |
@JsonView控制JSON输出方式
场景:假设在query()中,不希望返回用户的password,但是在getinfo()中可返回用户的password,在这两个服务中,返回不同的字段;
使用步骤
1.使用接口来声明多个视图
2.在值对象的get方法上指定视图
1 | public class User { |
3.在Controller方法上指定视图
1 | "/user",method = RequestMethod.GET) (value = |
重构
1 | "/user",method = RequestMethod.GET) (value = |
用户创建请求
1 |
|
@RequestBody 映射请求体到 JAVA方法的参数
1 |
|
日期类型参数的处理
为了解决每一个服务端所使用的时间展示方法不一样,有一些使用年月日,有一些使用时分秒;
后台采取时间戳的方式,传递时间数据;
最终的展示格式,由前端(服务端)进行自我定义;
@Valid注解和BindingResult验证请求参数的合法性并处理校验结果
1 |
|
1 |
|
为了对请求既能返回错误,又能对请求做出响应,则需要用上BindingResult;
带着错误信息进入到方法体中,继续执行;
1 |
|
控制台返回:may not be empty
用户修改请求
常用的验证注解
注解 | 解释 |
---|---|
@NotNull | 值不能为空 |
@Null | 值必须为空 |
@Pattern(regex=) | 字符串必须匹配正则表达式 |
@Size(min=,max=) | 集合的元素数量在范围内 |
@CreditCardNumber(ignoreNonDigitCharacters=) | 字符串必须是信用卡号 |
字符串必须是Email地址 | |
@Length(min=,max=) | 检查字符串的长度 |
@NotBlank | 字符串必须有字符 |
@NotEmpty | 字符串不为NULL,集合有元素 |
@Range(min=,max=) | 数字必须在范围内 |
@SafeHtml | 字符串是安全的HTML |
@URL | 字符串是合法的URL |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
1 |
|
1 | "/{id:\\d+}") ( |
控制台返回:
password may not be empty
birthday must be in the past
自定义错误消息
1 | "密码不能为空") (message = |
1 | if(errors.hasErrors()){ |
控制台返回:
密码不能为空
生日必须是过去的时间
自定义校验注解
1 | // 注解可标注在方法和字段上 |
1 | public class MyConstraintValidator implements ConstraintValidator<MyConstraint,Object>{ |
1 | "测试") (message = |
控制台返回:
My Constraint Validator Init
greeting
tom
测试
用户删除请求
1 |
|
1 | "/{id:\\d+}") ( |